#include <linux/init.h>//包含宏定义得头文件
#include <linux/module.h>//包含初始化加载模块得头文件
#include <linux/i2c.h> //

#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/input.h>

#include <linux/delay.h>
#include <linux/workqueue.h>
/****************I2c驱动框架driver文件创建*************
在没有设备树的情况下是需要client文件构建一个结构体来实现，查看client的节点在文件
/sys/bus/i2c/devices下的i2c0 创建文件定义client需要把设备树的节点去掉
* (1)调试方法:cat /proc/irq/4/spurious(可以查看打印)
* (2)
* (3)
* (4)
* (5)
***********************************************************************/
/*全局变量*/
#define DEVICE_MODE 0x00
#define ID_G_MODE   0xa4


int irq;
static struct device_node *ft5x05_device_node;//获取设备树的节点变量
static struct input_dev*ft5x06_dev;

static struct i2c_client*ft5x06_client;

/*函数申明*/
static int ft5x06_read_reg(u8 reg_addr);
static void ft5x06_write_reg(u8 reg_addr,u8 data,u8 len);
static void ft5x06_func(struct work_struct*work);

DECLARE_WORK(ft5x06_work,ft5x06_func);//动态注册一个工作对列ft5x06_work
//读函数 
static int ft5x06_read_reg(u8 reg_addr)
{
    u8 data;
    struct i2c_msg msgs[]={
        [0]={
            .addr =.ft5x06_client->addr,//用于获取probe函数中的client的值
            .flags=0,
            .len=sizeof(reg_addr),
            .buf=&reg_addr,
        },
        [1]={
            .addr =.ft5x06_client->addr,//用于获取probe函数中的client的值
            .flags=1,
            .len=sizeof(data),
            .buf=&data,
        },
    };
    i2c_transfer(ft5x06_client->adapter,msgs,2);
    return data;
}

/*iic写函数*/
static void ft5x06_write_reg(u8 reg_addr,u8 data,u8 len)
{
    u8 buff[256];
    struct i2c_msg msgs[]={
        [0]={
            .addr =.ft5x06_client->addr,//用于获取probe函数中的client的值
            .flags=0,
            .len=len+1,
            .buf=buff,
        },
    };
    buff[0]=reg_addr;
    memcpy(&buff[1],&data,len);//拼接数据函数
    i2c_transfer(ft5x06_client->adapter,msgs,1);
}
/*中断下文工作队列:获取到触摸屏坐标的X\Y坐标*/
static void ft5x06_func(struct work_struct*work)
{
    int TOUCH1_XH,TOUCH1XL,x;
    int TOUCH1_YH,TOUCH1YL,y;
    int TD_STATUS;
    //读取寄存器得数值
    TOUCH1_XH=ft5x06_read_reg(0X03);//使用读取IIC寄存器树值得函数
    TOUCH1XL=ft5x06_read_reg(0X04)
    //获取x坐标的值
    x=(TOUCH1_XH<<8)|(TOUCH1XL)&0x0fff;


    TOUCH1_YH=ft5x06_read_reg(0X05);
    TOUCH1YL=ft5x06_read_reg(0X06)
    //获取Y坐标的值
    y=(TOUCH1_YH<<8)|(TOUCH1YL)&0x0fff;

    //读取寄存器TD_STATUS的值
    TD_STATUS=ft5x06_read_reg(0x02);
    TD_STATUS=TD_STATUS&0xf;//获取没有手指在屏幕上
    if(TD_STATUS==0){//判断有没有手指按上，如果有的话要上报按下去的事件，没有就要上报抬手事件
        input_report_key(ft5x06_dev,BTN_TOUCH,0);
        input_sync(ft5x06_dev);
    }else{
        input_report_key(ft5x06_dev,BTN_TOUCH,1);//上报
        input_report_ads(ft5x06_dev,ABS_X,x);
        input_report_ads(ft5x06_dev,ABS_X,y);
        input_sync(ft5x06_dev);
    }
  
}

static irq_handler_t ft5x06_handler(int irq,void *args)
{
    schedule_work(&ft5x06_work);//中断下文
    return IRQ_HANDLED;
}

int ft5x06_probe(struct i2c_client*client,const struct i2c_device_id*id)
{
    int read_reg;
    int ft5x05_irq_gpio;
    int ft5x05_reset_gpio;
    printk("this i2c_probe ok\n");

    ft5x06_client=client;//因为我们需要在别的地方需要用到这个client，所以我们把他复制出来

/*获取设备树触摸芯片的节点*/
    ft5x05_device_node = of_find_node_by_path("/soc/aips-bus@02100000/i2c@021a4000/edt-ft5");
    if(ft5x05_device_node==NULL){
        printk("ft5x05_device_node error!");
        return -1；
    }
    printk("ft5x05_device_node is %s\n",ft5x05_device_node->name);
/*设备节点有两个gpio引脚需要获取irq_gpio、reset_gpio*/
    ft5x05_irq_gpio=of_get_named_gpio(test_device_node,"irq-gpio",0);//从设备树获取到 GPIO 编号
        if(ft5x05_irq_gpio<0)
        {
             printk("of_get_named_gpio ft5x05_irq_gpio error!\n");
             return -1；
        }
/*获取rest引脚GPIO号*/
    ft5x05_reset_gpio=of_get_named_gpio(test_device_node,"reset-gpio",0);
       if(ft5x05_reset_gpio<0)
        {
             printk("of_get_named_gpio ft5x05_reset_gpio error!\n");
             return -1；
        }
        printk("ft5x05_irq_gpio is :%d\n",ft5x05_irq_gpio);
        printk("ft5x05_reset_gpio is :%d\n",ft5x05_reset_gpio);

/*申请中断引脚*/
    gpio_free(ft5x05_irq_gpio);
    ret=gpio_request(ft5x05_irq_gpio,"irq_gpio");
    if(ret<0)
    {
        printk("gpio_request is error!\n");
        return -4
    }

    gpio_free(ft5x05_reset_gpio);
    ret=gpio_request(ft5x05_reset_gpio,"reset_gpio");
    if(ret<0)
    {
        printk("ft5x05_reset_gpio is error\n");
        return -5;
    }
    /*设置中断引脚方向*/
    gpio_direction_input(ft5x05_irq_gpio);
    /*设置复位引脚的方向为输出然后停止复位*/
    gpio_direction_output(ft5x05_reset_gpio,0);
    msleep(5);
    gpio_set_value(ft5x05_reset_gpio);//输出高电平
    
    /*获得中断号*/
    irq = gpio_to_irq(ft5x05_irq_gpio)
    /*申请中断号*/
    ret = request_irq(irq,ft5x06_handler,IRQF_TYPE_EDGE_FALLING|IRQF_ONEDHOT,"ft5x06_irq",NULL);
        if(ret<0)
        {
            printk("request_irq error!\n");
            goto error_request_irq;
        }

    //设置工作模式为正常模式
    ft5x06_write_reg(DEVICE_MODE,0,1);
    
    ft5x06_write_reg(ID_G_MODE,1,1);
    // //读取寄存器地址为0x80的数据
    // read_reg=ft5x06_read_reg(0x80);

/*输入子系统初始化*/
    ft5x06_dev=input_allocate_device();
    ft5x06_dev->name="ft5x06_input_test"

    _set_bit(EV_KEY,ft5x06_dev->evbit);//支持按键事件
    _set_bit(KEY_1,ft5x06_dev->evbit);//支持绝对坐标事件
    _set_bit(BTN_TOUCH,ft5x06_dev->evbit);//支持按键检测

    _set_bit(ABS_X,ft5x06_dev->absbit);//支持X坐标
    _set_bit(ABS_Y,ft5x06_dev->absbit);//支持按键检测
    _set_bit(ABS_PRESSURE,ft5x06_dev->keybit);//支持压力检测

    input_set_abs_params(ft5x06_dev,ABS_X,0,1024,0,0);//设置屏幕X轴范围
    input_set_abs_params(ft5x06_dev,ABS_Y,0,600,0,0);//设置屏幕Y轴范围
    input_set_abs_params(ft5x06_dev,ABS_PRESSURE,0,255,0,0);//设置压力值

    input_reg=input_register_device(ft5x06_dev);

    if(input_reg<0)
    {
        printk("input_register_device error!\n");
        goto  error_input_register;
    }


 
    return 0;

error_request_irq:
    free_irq(irq,NULL);
    return ret;
error_input_register:
    free_irq(irq,NULL);
    input_unregister_device(ft5x06_dev);//注销input
    input_free_device(ft5x06_dev);//释放input
    return ret; 
}

int ft5x06_remove(struct i2c_client*i2c_client)
{
    printk("this i2c_remove ok\n");
    return 0;
}

static const struct of_device_id ft5x06_id[]={
    {.compatible="edt,edt-ft5306",0},
    {.compatible="edt,edt-ft5306",0},
    {.compatible="edt,edt-ft5306",0},

};
static const struct i2c_device_id i2c_id_ts[]={
    {"xxx",0},
    {}
}

/*初始化i2c结构*/
static struct i2c_driver ft5x06_driver={
    .driver={
        .owner=THIS_MODULE,
        .name="ft5x06_test",
        .of_match_table=ft5x06_id,
    },
    .pobe=ft5x06_probe,
    .remove=ft5x06_remove,
    .id_table=&i2c_id_ts
};

static int ft5x05_driver_init(void)
{
   int i2c_reg;
   i2c_reg=i2c_add_driver(&ft5x06_driver);//注册进内核中
   if(i2c_reg<0)
   {
       printk("this i2c_add_driver error\n");
        return i2c_reg;
   }
   printk("this ft5x05_driver_init\n");
   return 0;
}


static void ft5x05_driver_exit(void)//退出函数没有返回值
{
    printk("this ft5x05_driver_exit\n");
    free_irq(irq,NULL);
    input_unregister_device(ft5x06_dev);//注销input
    input_free_device(ft5x06_dev);//释放input
    i2c_del_driver(&ft5x06_driver);
}
/*功能实现*/

module_init(ft5x05_driver_init);
module_exit(ft5x05_driver_exit);
/*驱动的出口与入口函数都在此处*/
MODULE_LICENSE("GPL");
/*申明信息*/
